
#include "freespace-sample-v1.h"

namespace freespace_sample_v1
{
	class FreespaceSampleVars : public SessionSampleVars
	{
	public:
		SPADAS_VARS(FreespaceSample, SessionSampleVars)
		FreespaceSampleData data;

		SessionGeneralSample toGeneralSample()
		{
			SessionGeneralSample sample;
			sample.timestamp() = timestamp;

			UInt pointCount = 0;
			for (UInt i = 0; i < data.sequences.size(); i++)
			{
				pointCount += data.sequences[i].points.size();
			}

			Array<GeneralElement> values(1 + 2 * (data.sequences.size() + pointCount));
			sample.values() = values;

			UInt seqBase = 1;
			UInt ptBase = seqBase + 2 * data.sequences.size();

			values[0] = data.sequences.size();

			pointCount = 0;
			for (UInt i = 0; i < data.sequences.size(); i++)
			{
				Array<Point2D> pts = data.sequences[i].points;

				values[seqBase + 2 * i] = pointCount;
				values[seqBase + 2 * i + 1] = pts.size();

				for (UInt n = 0; n < pts.size(); n++)
				{
					values[ptBase + 2 * (pointCount + n)] = pts[n].x;
					values[ptBase + 2 * (pointCount + n) + 1] = pts[n].y;
				}

				pointCount += pts.size();
			}

			sample.significantCount() = values.size();
			return sample;
		}

		Bool fromSample(String protocol, SessionSample sample) override
		{
			if (protocol.startsWith("freespace-sample-v1"))
			{
				SessionGeneralSample generalSample = sample.as<SessionGeneralSample>();
				timestamp = generalSample.timestamp();
				Array<GeneralElement> values = generalSample.values();

				if (values.size() < 1) return FALSE;

				UInt seqCount = (UInt)values[0].value;
				if (seqCount == 0)
				{
					data.sequences = Array<FreespacePointSequence>();
					return TRUE;
				}

				UInt seqBase = 1;
				if (values.size() < seqBase + 2 * seqCount) return FALSE;

				data.sequences = Array<FreespacePointSequence>(seqCount);

				UInt totalPoints = 0;
				for (UInt i = 0; i < seqCount; i++)
				{
					UInt pointCount = (UInt)values[seqBase + 2 * i + 1].value;
					totalPoints += pointCount;
					data.sequences[i].points = Array<Point2D>(pointCount);
				}

				UInt ptBase = seqBase + 2 * seqCount;
				if (values.size() < ptBase + 2 * totalPoints) return FALSE;

				UInt pointIndex = 0;
				for (UInt i = 0; i < seqCount; i++)
				{
					Array<Point2D>& points = data.sequences[i].points;
					for (UInt n = 0; n < points.size(); n++)
					{
						points[n].x = values[ptBase + 2 * pointIndex].value;
						points[n].y = values[ptBase + 2 * pointIndex + 1].value;
						pointIndex++;
					}
				}

				return TRUE;
			}
			return FALSE;
		}
	};
}

using namespace freespace_sample_v1;

FreespaceSample::FreespaceSample() : Object<FreespaceSampleVars>(new FreespaceSampleVars, TRUE)
{}

FullTimestamp& FreespaceSample::timestamp()
{
	return vars->timestamp;
}

FreespaceSampleData *FreespaceSample::operator ->()
{
    return &vars->data;
}

String FreespaceSample::getProtocolName(UInt channel)
{
    return (String)"freespace-sample-v1@" + channel;
}

SessionGeneralSample FreespaceSample::toGeneralSample()
{
    return vars->toGeneralSample();
}

Array<String> FreespaceSample::getProtocolNames(UInt channel)
{
	return Array<String>::create(1, "freespace-sample-v1").convert<String>([channel](auto& s){ return s + "@" + channel; });
}

Bool FreespaceSample::fromGeneralSample(String protocol, SessionGeneralSample generalSample)
{
    return vars->fromSample(protocol, generalSample.as<SessionSample>());
}